﻿
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace EmperialApps.WeatherSpark.Service.Internal {

    /// <summary>Acts as a storage and retrieval system for forecast subscriptions, backed by an Azure table container.</summary>
    internal sealed class SubscriptionsTableStore {

        private const string SubscriptionsTableName = "subscriptions";

        private readonly CloudTable _table;


        /// <summary>Initializes a new instance of the <see cref="SubscriptionsTableStore"/> class.</summary>
        public SubscriptionsTableStore( CloudStorageAccount account ) {
            var client = account.CreateCloudTableClient( );
            this._table = client.GetTableReference( SubscriptionsTableName );
#if DEBUG
            TraceEventType.Warning.Trace( "Deleting existing subscriptions table!" );
            bool deleted = _table.DeleteIfExists( );
#endif
            bool created = _table.CreateIfNotExists( );
        }


        /// <summary>Adds a subscription to the table.</summary>
        public void Add( Subscription subscription ) {
            var operation = TableOperation.InsertOrReplace( subscription );
            var response = this._table.Execute( operation );
            response.Trace( "Adding", typeof( Subscription ) );
        }

        /// <summary>Updates the <see cref="Subscription.ChannelUri"/> of a subscription in the table.</summary>
        public bool Update( Subscription subscription ) {
            // Search for an existing matching subscription.
            var existingSubscription = this._table.Retrieve( subscription );

            // If the subscription has a different ChannelUri, update it.
            bool update = Subscription.Update( existingSubscription, subscription );
            if( update ) {
                var operation = TableOperation.Replace( existingSubscription );
                var response = this._table.Execute( operation );
                response.Trace( "Updating", typeof( Subscription ) );
            }

            return update;
        }

        /// <summary>Removes a subscription from the table.</summary>
        public bool Remove( Subscription subscription ) {
            // Search for an existing matching subscription.
            var existingSubscription = this._table.Retrieve( subscription );

            // If the subscription was found, remove it.
            if( existingSubscription != null ) {
                var operation = TableOperation.Delete( existingSubscription );
                try {
                    var response = this._table.Execute( operation );
                    response.Trace( "Removing", typeof( Subscription ) );
                }
                catch( StorageException ex ) {
                    if( ex.Message.Contains( "(404)" ) )
                        existingSubscription = null;
                    else
                        throw;
                }
            }

            return existingSubscription != null;
        }

        /// <summary>Moves a subscription in the table to a different location.</summary>
        public void Move( Subscription subscription, string locationName ) {
            if( this.Remove( subscription ) ) {
                subscription.PartitionKey = locationName;
                this.Add( subscription );
            }
        }

        /// <summary>Gets all subscriptions for the specified named location.</summary>
        public IEnumerable<Subscription> Get( string locationName ) {
            var query = new TableQuery<Subscription>( )
                .Where( TableQuery.GenerateFilterCondition( "PartitionKey", QueryComparisons.Equal, locationName ) );

            try {
                return this._table.ExecuteQuery( query ).ToList( );
            }
            catch( StorageException ex ) {
                ex.Trace( "Subscription enumerator failure" );

                return this._table.ExecuteQuery( query ).ToList( );
            }
        }

    }

}
